import { Node, NodePool, Prefab, instantiate, isValid, Component } from 'cc';
import { Log } from '../logger/LoggerGlobal';

/**
 * 节点池配置接口
 */
export interface INodePoolConfig {
    /** 预创建节点数量 */
    preloadCount?: number;
    /** 最大节点数量 */
    maxCount?: number;
    /** 是否启用统计 */
    enableStats?: boolean;
    /** 节点初始化回调 */
    onNodeCreate?: (node: Node) => void;
    /** 节点重用回调 */
    onNodeReuse?: (node: Node) => void;
    /** 节点回收回调 */
    onNodeRecycle?: (node: Node) => void;
}

/**
 * 节点池统计信息
 */
export interface INodePoolStats {
    /** 当前池中节点数量 */
    poolSize: number;
    /** 当前使用中的节点数量 */
    activeCount: number;
    /** 累计创建次数 */
    totalCreated: number;
    /** 累计获取次数 */
    totalGet: number;
    /** 累计回收次数 */
    totalRecycle: number;
    /** 命中率（从池中获取的比例） */
    hitRate: number;
}

/**
 * 节点池包装类
 */
class NodePoolWrapper {
    public readonly pool: NodePool;
    public readonly prefab: Prefab;
    private readonly config: INodePoolConfig;
    
    // 统计数据
    private stats = {
        totalCreated: 0,
        totalGet: 0,
        totalRecycle: 0,
        activeCount: 0,
    };

    constructor(prefab: Prefab, config: INodePoolConfig = {}) {
        this.prefab = prefab;
        this.config = {
            preloadCount: 5,
            maxCount: 50,
            enableStats: true,
            ...config,
        };

        // 创建节点池
        this.pool = new NodePool();
    }

    /**
     * 预加载节点
     */
    public async preload(): Promise<void> {
        const count = this.config.preloadCount || 0;
        const nodes: Node[] = [];
        
        for (let i = 0; i < count; i++) {
            const node = this.createNode();
            if (node) {
                nodes.push(node);
            }
        }

        // 将创建的节点放入池中
        nodes.forEach(node => {
            this.pool.put(node);
        });
    }

    /**
     * 创建新节点
     */
    private createNode(): Node | null {
        try {
            const node = instantiate(this.prefab);
            
            if (this.config.enableStats) {
                this.stats.totalCreated++;
            }

            // 调用创建回调
            if (this.config.onNodeCreate) {
                this.config.onNodeCreate(node);
            }

            return node;
        } catch (error) {
            Log.resource.error('创建节点失败', { error });
            return null;
        }
    }

    /**
     * 从池中获取节点
     */
    public get(): Node | null {
        if (this.config.enableStats) {
            this.stats.totalGet++;
        }

        let node: Node | null = null;

        // 尝试从池中获取
        if (this.pool.size() > 0) {
            node = this.pool.get();
        } else {
            // 池为空，检查是否超过最大限制
            const maxCount = this.config.maxCount || Infinity;
            if (this.stats.activeCount < maxCount) {
                node = this.createNode();
            } else {
                Log.resource.warn('节点池已达到最大数量限制', { maxCount });
                return null;
            }
        }

        if (node && isValid(node)) {
            if (this.config.enableStats) {
                this.stats.activeCount++;
            }

            // 调用重用回调
            if (this.config.onNodeReuse) {
                this.config.onNodeReuse(node);
            }

            return node;
        }

        return null;
    }

    /**
     * 回收节点到池中
     */
    public put(node: Node): void {
        if (!node || !isValid(node)) {
            Log.resource.warn('尝试回收无效节点');
            return;
        }

        if (this.config.enableStats) {
            this.stats.totalRecycle++;
            this.stats.activeCount = Math.max(0, this.stats.activeCount - 1);
        }

        // 调用回收回调
        if (this.config.onNodeRecycle) {
            this.config.onNodeRecycle(node);
        }

        // 重置节点状态
        node.removeFromParent();
        node.setPosition(0, 0, 0);
        node.setRotation(0, 0, 0, 1);
        node.setScale(1, 1, 1);
        node.active = true;

        // 放入池中
        this.pool.put(node);
    }

    /**
     * 获取统计信息
     */
    public getStats(): INodePoolStats {
        const totalFromPool = this.stats.totalGet - (this.stats.totalCreated - this.pool.size());
        const hitRate = this.stats.totalGet > 0 ? totalFromPool / this.stats.totalGet : 0;

        return {
            poolSize: this.pool.size(),
            activeCount: this.stats.activeCount,
            totalCreated: this.stats.totalCreated,
            totalGet: this.stats.totalGet,
            totalRecycle: this.stats.totalRecycle,
            hitRate: Math.max(0, Math.min(1, hitRate)),
        };
    }

    /**
     * 清理池中所有节点
     */
    public clear(): void {
        this.pool.clear();
        this.stats.activeCount = 0;
    }

    /**
     * 获取池大小
     */
    public size(): number {
        return this.pool.size();
    }
}

/**
 * 节点池管理器
 * 支持MVVM和ECS架构的统一节点池管理
 * 
 * 特性：
 * - 单例模式，全局统一管理
 * - 支持预加载和懒加载
 * - 自动节点生命周期管理
 * - 完整的统计和监控
 * - 支持自定义回调钩子
 * - 内存池大小限制
 * - 适配MVVM的View组件和ECS的Entity
 */
export class NodePoolManager {
    private static _instance: NodePoolManager;
    
    /** 节点池集合 key: poolId */
    private readonly pools: Map<string, NodePoolWrapper> = new Map();
    
    /** 节点到池ID的映射，用于快速查找 */
    private readonly nodeToPoolId: WeakMap<Node, string> = new WeakMap();
    
    /** 是否启用全局统计 */
    private enableGlobalStats: boolean = true;

    private constructor() {
        // 私有构造函数，确保单例
    }

    /**
     * 获取单例实例
     */
    public static getInstance(): NodePoolManager {
        if (!NodePoolManager._instance) {
            NodePoolManager._instance = new NodePoolManager();
        }
        return NodePoolManager._instance;
    }

    /**
     * 创建节点池
     * @param poolId 节点池唯一标识
     * @param prefab 预制体
     * @param config 配置选项
     */
    public createPool(poolId: string, prefab: Prefab, config?: INodePoolConfig): void {
        if (!poolId) {
            throw new Error('节点池ID不能为空');
        }

        if (!prefab) {
            throw new Error('预制体不能为空');
        }

        if (this.pools.has(poolId)) {
            Log.resource.warn('节点池已存在，将被覆盖', { poolId });
            this.clearPool(poolId);
        }

        const wrapper = new NodePoolWrapper(prefab, config);
        this.pools.set(poolId, wrapper);
    }

    /**
     * 预加载节点池
     * @param poolId 节点池ID
     */
    public async preloadPool(poolId: string): Promise<void> {
        const wrapper = this.pools.get(poolId);
        if (!wrapper) {
            throw new Error(`节点池 ${poolId} 不存在`);
        }

        await wrapper.preload();
    }

    /**
     * 批量预加载多个节点池
     * @param poolIds 节点池ID数组
     */
    public async preloadPools(poolIds: string[]): Promise<void> {
        const promises = poolIds.map(id => this.preloadPool(id).catch(err => {
            Log.resource.error('预加载节点池失败', { poolId: id, error: err });
        }));
        await Promise.all(promises);
    }

    /**
     * 从节点池获取节点
     * @param poolId 节点池ID
     * @returns 节点实例，如果失败返回null
     */
    public getNode(poolId: string): Node | null {
        const wrapper = this.pools.get(poolId);
        if (!wrapper) {
            Log.resource.error('节点池不存在', { poolId });
            return null;
        }

        const node = wrapper.get();
        if (node) {
            this.nodeToPoolId.set(node, poolId);
        }

        return node;
    }

    /**
     * 获取节点并添加到父节点
     * @param poolId 节点池ID
     * @param parent 父节点
     * @returns 节点实例
     */
    public getNodeWithParent(poolId: string, parent: Node): Node | null {
        const node = this.getNode(poolId);
        if (node && parent && isValid(parent)) {
            parent.addChild(node);
        }
        return node;
    }

    /**
     * 获取节点并获取指定组件
     * @param poolId 节点池ID
     * @param componentType 组件类型
     * @returns 组件实例
     */
    public getNodeWithComponent<T extends Component>(
        poolId: string,
        componentType: { new(): T }
    ): { node: Node; component: T } | null {
        const node = this.getNode(poolId);
        if (!node) {
            return null;
        }

        let component = node.getComponent(componentType);
        if (!component) {
            component = node.addComponent(componentType);
        }

        return component ? { node, component } : null;
    }

    /**
     * 回收节点
     * @param node 要回收的节点
     * @param poolId 可选的节点池ID，如果不提供则自动查找
     */
    public putNode(node: Node, poolId?: string): void {
        if (!node || !isValid(node)) {
            Log.resource.warn('尝试回收无效节点');
            return;
        }

        // 如果没有提供poolId，尝试从映射中查找
        if (!poolId) {
            poolId = this.nodeToPoolId.get(node);
        }

        if (!poolId) {
            Log.resource.warn('无法确定节点所属的节点池，节点将被销毁');
            node.destroy();
            return;
        }

        const wrapper = this.pools.get(poolId);
        if (!wrapper) {
            Log.resource.warn('节点池不存在，节点将被销毁', { poolId });
            node.destroy();
            return;
        }

        wrapper.put(node);
    }

    /**
     * 批量回收节点
     * @param nodes 节点数组
     * @param poolId 可选的节点池ID
     */
    public putNodes(nodes: Node[], poolId?: string): void {
        nodes.forEach(node => this.putNode(node, poolId));
    }

    /**
     * 清空指定节点池
     * @param poolId 节点池ID
     */
    public clearPool(poolId: string): void {
        const wrapper = this.pools.get(poolId);
        if (wrapper) {
            wrapper.clear();
        }
    }

    /**
     * 删除节点池
     * @param poolId 节点池ID
     */
    public removePool(poolId: string): void {
        const wrapper = this.pools.get(poolId);
        if (wrapper) {
            wrapper.clear();
            this.pools.delete(poolId);
        }
    }

    /**
     * 清空所有节点池
     */
    public clearAll(): void {
        this.pools.forEach(wrapper => wrapper.clear());
        this.pools.clear();
    }

    /**
     * 获取节点池统计信息
     * @param poolId 节点池ID
     */
    public getPoolStats(poolId: string): INodePoolStats | null {
        const wrapper = this.pools.get(poolId);
        return wrapper ? wrapper.getStats() : null;
    }

    /**
     * 获取所有节点池的统计信息
     */
    public getAllStats(): Map<string, INodePoolStats> {
        const stats = new Map<string, INodePoolStats>();
        this.pools.forEach((wrapper, poolId) => {
            stats.set(poolId, wrapper.getStats());
        });
        return stats;
    }

    /**
     * 获取节点池大小
     * @param poolId 节点池ID
     */
    public getPoolSize(poolId: string): number {
        const wrapper = this.pools.get(poolId);
        return wrapper ? wrapper.size() : 0;
    }

    /**
     * 检查节点池是否存在
     * @param poolId 节点池ID
     */
    public hasPool(poolId: string): boolean {
        return this.pools.has(poolId);
    }

    /**
     * 获取所有节点池ID
     */
    public getAllPoolIds(): string[] {
        return Array.from(this.pools.keys());
    }

    /**
     * 打印所有节点池的统计信息（调试用）
     */
    public printStats(): void {
        Log.performance.info('======== 节点池统计信息 ========');
        this.pools.forEach((wrapper, poolId) => {
            const stats = wrapper.getStats();
            Log.performance.info(`[${poolId}]`, {
                '池大小': stats.poolSize,
                '活跃节点': stats.activeCount,
                '总创建': stats.totalCreated,
                '总获取': stats.totalGet,
                '总回收': stats.totalRecycle,
                '命中率': `${(stats.hitRate * 100).toFixed(2)}%`,
            });
        });
        Log.performance.info('===============================');
    }

    /**
     * 设置是否启用全局统计
     */
    public setEnableGlobalStats(enable: boolean): void {
        this.enableGlobalStats = enable;
    }
}

/**
 * 导出单例实例
 */
export const nodePoolManager = NodePoolManager.getInstance();
